/*
  Minecraft Controller
 

 
 Created on 29 Dec 2013
 by Stefano Ricci


 */

#include <Esplora.h>
#include <CheckButton.h>

int xOffsetJ;
int yOffsetJ;

int xOffsetA;
int yOffsetA;

typedef enum {
  ST_IDLE = 0,
  ST_RUNNING = 1
} status_t;

#define JOYSTICK_THRESHOLD       200
#define ACCELEROMETER_THRESHOLD   50

void setup()
{
  Serial.begin(9600);                                  // initialize serial communication with your computer
  xOffsetJ = Esplora.readJoystickX();                  // read the joystick's rest X position
  yOffsetJ = Esplora.readJoystickY();                  // read the joystick's rest Y position
  xOffsetA = Esplora.readAccelerometer(X_AXIS);;       // read the accelerometer's X axis value
  yOffsetA = Esplora.readAccelerometer(Y_AXIS);        // read the accelerometer's Y axis value
} 

CheckButton btnDown(SWITCH_DOWN);
CheckButton btnUp(SWITCH_UP);

void loop() 
{
  unsigned long ms = millis();
  
  static status_t controllerStatus = ST_IDLE;
  static unsigned long idleMsgTime = ms;  
  static unsigned long joystickTime = ms;
  static unsigned long acceleratorTime = ms;
  
  

  switch (controllerStatus) {
    
    case ST_IDLE:
    {
      //wait for double click on SWITCH_DOWN to initialize  

      if (btnDown.check() == CB_DCLICK) {
        controllerStatus = ST_RUNNING;
        Keyboard.begin();
        Mouse.begin();
        Esplora.writeGreen(10);
        joystickTime = acceleratorTime = millis();
        Serial.println("MinecraftController entering the running state - double click on SWITCH_UP to pause");
        break;
      } 
      
      ms = millis();
      if (ms - idleMsgTime > 10000) {
          Serial.println("Please double click on SWITCH_DOWN to start operate");
          idleMsgTime = ms;
      }
    }
    break;
    
    case ST_RUNNING:
    {
      if (btnUp.check() == CB_DCLICK) {
        controllerStatus = ST_IDLE;
        Keyboard.releaseAll();
        Keyboard.end();
        Mouse.end();        
        Esplora.writeGreen(0);
        idleMsgTime = millis();
        Serial.println("MinecraftController entering the idle state - double click on SWITCH_DOWN to start operate");
        break;
      }
      
      manageJoystick(); // move characther
      
      ms = millis();
//      if (ms - joystickTime > 10) {
//        manageJoystick(); // move characther
//        joystickTime = ms;
//      }
      
      if (ms - acceleratorTime > 10) {
        manageAccelerometer(); // change view
        acceleratorTime = ms;
      }
      
      manageKeys();
    }
    break;
      
  }
  return;
}    

void manageJoystick() 
{
  /*
   * In Minecraft it is important how long a movement key is pressed, not how many times
   * This means we need to use Keyboard.press()/release() and not Keyboard.write()
   */
   
  static char upDownStatus = '\0';
  static char leftRightStatus = '\0';
  
  int xValue = Esplora.readJoystickX();        // read the joystick's X position
  int yValue = Esplora.readJoystickY();        // read the joystick's Y position
  
  int deltaX = - xValue + xOffsetJ;             // joystick X values grows on the left
  int deltaY = - yValue + yOffsetJ;             // joystick Y values grows when moving down

  char currStatus = '\0';      
  
  currStatus = (char)tristate(deltaX, (-1)*JOYSTICK_THRESHOLD, JOYSTICK_THRESHOLD, 'A', '\0', 'D');
  if (currStatus != leftRightStatus) {
    Serial.print("LR changed: "); Serial.print(leftRightStatus?leftRightStatus:' '); Serial.print("-->"); Serial.println(currStatus?currStatus:' ');
    if (leftRightStatus != '\0') Keyboard.release(leftRightStatus);
    if (currStatus != '\0') Keyboard.press(currStatus);
    leftRightStatus = currStatus;
  }
//  if (deltaX > JOYSTICK_THRESHOLD) {
//    c = 'D'; // move to the right
//  } else if (deltaX < (-1)*JOYSTICK_THRESHOLD) {
//    c = 'A'; // move to the left
//  }
//  if (c != '\0') {
//    Keyboard.press(c);
//    delay(10);
//    Keyboard.release(c);
//    //Keyboard.write(c);
//  }
  
  currStatus = (char)tristate(deltaY, (-1)*JOYSTICK_THRESHOLD, JOYSTICK_THRESHOLD, 'S', '\0', 'W');
  if (currStatus != upDownStatus) {
    Serial.print("UD changed: "); Serial.print(upDownStatus?upDownStatus:' '); Serial.print("-->"); Serial.println(currStatus?currStatus:' ');
    if (upDownStatus != '\0') Keyboard.release(upDownStatus);
    if (currStatus != '\0') Keyboard.press(currStatus);
    upDownStatus = currStatus;
  }  
//  c = '\0';      
//  if (deltaY > JOYSTICK_THRESHOLD) {
//    c = 'W'; // move forward
//  } else if (deltaY < (-1)*JOYSTICK_THRESHOLD) {
//    c = 'S'; // move backward
//  }
}

int tristate(int input, int lowThreshold, int highThreshold, int lowValue, int middleValue, int highValue)
{
  if (input <= lowThreshold) return lowValue;
  if (input >= highThreshold) return highValue;
  return middleValue;
}

void manageAccelerometer() 
{
  int x_axis = Esplora.readAccelerometer(X_AXIS);
  int y_axis = Esplora.readAccelerometer(Y_AXIS);
  //int z_axis = Esplora.readAccelerometer(Z_AXIS);
   
  //int mouseX = map( x_axis-xOffsetA,-180, 180, 10, -10);  // map the X value to a range of movement for the mouse X
  //int mouseY = map( y_axis-yOffsetA,-180, 180, 10, -10);  // map the Y value to a range of movement for the mouse Y
  
  int deltaX = x_axis-xOffsetA;
  int deltaY = y_axis-yOffsetA;
  
  int mouseX = tristate(deltaX, (-1)*ACCELEROMETER_THRESHOLD, ACCELEROMETER_THRESHOLD, 10, 0, -10);
  int mouseY = tristate(deltaY, (-1)*ACCELEROMETER_THRESHOLD, ACCELEROMETER_THRESHOLD, 10, 0, -10);
  
  if (mouseX != 0 || mouseY != 0) {
    Mouse.move(mouseX, mouseY, 0);                         // move the mouse  
  }
}

void manageKeys() {
}


